Uso básico da linguagem
Atrubuição de variáveis
n <- ((5 + 5) * 4) / 2
n
[1] 20
sqrt(n + 5) -> sq
sq
[1] 5
sq ^ 3
[1] 125
Vetores
v <- c(1,2,3,4,5)
v
[1] 1 2 3 4 5
v <- 1:5
v
[1] 1 2 3 4 5
seq(5) -> v
v
[1] 1 2 3 4 5
v <- seq.int(from = 1, to = 5, by = 1)
v
[1] 1 2 3 4 5
Vetores podem ter seus índices nomeados:
v_names <- c("um", "dois", "três", "quatro", "cinco")
names(v) <- v_names
v
um dois três quatro cinco
1 2 3 4 5
Filtragem
Vetores podem ser filtrados por range
v[1:3]
um dois três
1 2 3
Também podem ser filtrados através de condicionais. O caso abaixo retorna um vetor de boleanos que satisfaça a condição:
v > 3
um dois três quatro cinco
FALSE FALSE FALSE TRUE TRUE
Para retornar os valores este vetor de boleanos deve ir dentro da indexação:
v[v>3]
quatro cinco
4 5
Matrizes
Matrizes só podem ter um tipo de valor. Inicialização:
m1 <- matrix(1:20, nrow = 4, ncol = 5)
m1
[,1] [,2] [,3] [,4] [,5]
[1,] 1 5 9 13 17
[2,] 2 6 10 14 18
[3,] 3 7 11 15 19
[4,] 4 8 12 16 20
Operações com matrizes
A lógica para operações com escalares é a mesma para vetores:
m1 * 5
[,1] [,2] [,3] [,4] [,5]
[1,] 5 25 45 65 85
[2,] 10 30 50 70 90
[3,] 15 35 55 75 95
[4,] 20 40 60 80 100
Em operações com vetores e matrizes cada coluna da matriz é percorrida pelo vetor em ordem e depois se repete:
m1 * v
[,1] [,2] [,3] [,4] [,5]
[1,] 1 25 36 39 34
[2,] 4 6 50 56 54
[3,] 9 14 11 75 76
[4,] 16 24 24 16 100
Os valores de duas matrize podem ser operados se elas possuirem a mesma quantidade de linhas e colunas:
m2 <- matrix(20:39, nrow = 4, ncol = 5)
m1 * m2
[,1] [,2] [,3] [,4] [,5]
[1,] 20 120 252 416 612
[2,] 42 150 290 462 666
[3,] 66 182 330 510 722
[4,] 92 216 372 560 780
m1 + m2
[,1] [,2] [,3] [,4] [,5]
[1,] 21 29 37 45 53
[2,] 23 31 39 47 55
[3,] 25 33 41 49 57
[4,] 27 35 43 51 59
Para de fato multiplcar duas matrizes a regra matemática precisa se respeitada (l1 = c2). O operador correto é %*%
m3 <- matrix(1:20, nrow = 5, ncol = 4)
m1 %*% m3
[,1] [,2] [,3] [,4]
[1,] 175 400 625 850
[2,] 190 440 690 940
[3,] 205 480 755 1030
[4,] 220 520 820 1120
Funções Internas
Funções para aritimética em geral
Soma (sum).
Soma todos os valores de um vetor
random_vec <- sample(30)
random_vec
[1] 2 26 29 18 22 3 1 25 10 28 30 19 13 17 20 4 15 9 21 23 16 7 14 8 6 12 5 27 24 11
sum(random_vec)
[1] 465
Também pode ser utilizado junto com filtragem, para contar a quantidade de ocorrencias dada uma determinada condição:
sum(mtcars$gear == 4)
[1] 12
Neste caso o resultado indicad que a tabela “mtcars” possui 12 ocorrencias cuja coluna gear é igaual a 4, ou seja, 12 carros de 4 marchas
Média Aritimética símples
\(\bar{x} = \frac{\sum_{i=1}^n x_{i}}{n}\)
vec_m <- c(1,2,3,4,5,6,7,8,9,10,30)
mean(vec_m)
[1] 7.727273
\(\sigma = \sqrt{\frac{\sum_{i=1(xi_{i} - \bar{x})^2}^{n}}{n}}\)
vec_var <- sample(20)
vec_var
[1] 6 1 11 16 3 5 7 8 17 10 2 14 19 15 4 20 12 18 9 13
sd(vec_var)
[1] 5.91608
\(Y_{i} = \beta_{0}+\beta_{1}X_{i}+\xi\)
Exemplo: Relação entre peso e altura em mulheres:
women
regWomen <- lm(women$height ~ women$weight)
summary(regWomen)
Call:
lm(formula = women$height ~ women$weight)
Residuals:
Min 1Q Median 3Q Max
-0.83233 -0.26249 0.08314 0.34353 0.49790
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 25.723456 1.043746 24.64 2.68e-12 ***
women$weight 0.287249 0.007588 37.85 1.09e-14 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.44 on 13 degrees of freedom
Multiple R-squared: 0.991, Adjusted R-squared: 0.9903
F-statistic: 1433 on 1 and 13 DF, p-value: 1.091e-14
PONTOS IMPORTANTES:
o p-value o nível de coorrelação entre as variáveis. Abaixo de 0.05 está dentro do intervalo de confiança de 95%
O R ajustado indica a capacidade de explicação das variáveis no modelo.
O resultado possui um p-value extremamente baixo: \(1.91^{-14}\), ou seja, alta coorrelação entre as variáveis.
O R ajustado de 0.9903 indica que este modelo tem capacida de explicação em 99.03%.
Gráficos
Plot
Plota de acordo com a serie de dados. No exemplo abaixo cada valor é representado por um ponto no eixo cartesiano:
plot(x = cars$speed, y = cars$dist, main = "Distâncias de parada", xlab = "Velocidade", ylab = "Distância")
#Também é possível interferir no gráfico que foi plotado. Os dois comandos devem ser executados juntos.
lines (c(5,25),c(5,80), col='red')

Outros tipos de séries exibirão outros visuais:
plot(UKDriverDeaths)

Ao plotar o resultado de uma regressão linear vários tipos de gráficos serão exibidos:
plot(regWomen)




Boxplot
Representa graficamente os valores do mínimo, 1,2 e 3 quartil, mediana e máximo.
boxplot(airquality)

Histograma
Histograma das frequencias de um dataset
hist(mtcars$mpg)

Dplyr
Select
Retorna um subset com a sleção de colunas filtradas
select(mtcars, mpg,hp,qsec,gear)
Também pode ser usado com ranges:
select(mtcars, hp:gear)
Filter
Filtra linhas de acordo com condições. Operadores binários podem ser utilizados
filter(mtcars, hp > 100, wt < 3.000 | qsec > 20.1)
Arrange
Ordena a tabela de acordo com as variáveis fornecidas. No caso abaixo o primeiro critério de ordenação é a quantidade de cilindros crescente e o segundo é a quantidade de marchas decrescente.
arrange(mtcars, cyl, desc(gear))
Mutate
Insere novas variáveis na tabela. É possível utilizar outras variáveis como base para os valores
mutate(USArrests, murder_prop = Murder / (Assault + Rape))
Pipes
É possível encadear todas estas funções com um pipe ( %>% ):
airquality %>% filter(Month == 8) %>% select(Ozone,Temp,Wind) %>% mutate(vento_ao_quadrado = Wind ** 2)
### Pacotes para gráficos #### Ggplot2 Cria gráficos visualmente agradáveis com bastante controle. funciona com a seguinte sintaxe:
ggplot2(dataset, aes(vaX,varY,…)) + função_de_plotagem() + função_de_plotagem() + …
primeiro é criada a area de plotagem com os parâmetros básicos. Em seguida cada função somada é adcionada ao plot.
ggplot(women, aes(women$height,women$weight)) + geom_point(col='red') + geom_path(col='#333333')

ggplot(cars, aes(cars$speed,cars$dist)) + geom_count()

Plotly
Cria gráficos interativos com excelentes recursos, mas funciona com sistema de visualizador. Se o tipo de gráfico não for fornecido ele tentará deduzir
obs: neste pacote caractere ‘~’ não significa em função de.
plot_ly(economics, x = ~date, y = ~pop)
No trace type specified:
Based on info supplied, a 'scatter' trace seems appropriate.
Read more about this trace type -> https://plot.ly/r/reference/#scatter
No scatter mode specifed:
Setting the mode to markers
Read more about this attribute -> https://plot.ly/r/reference/#scatter-mode
No trace type specified:
Based on info supplied, a 'scatter' trace seems appropriate.
Read more about this trace type -> https://plot.ly/r/reference/#scatter
No scatter mode specifed:
Setting the mode to markers
Read more about this attribute -> https://plot.ly/r/reference/#scatter-mode
#se apenas um eixo for fornecido criará um histograma
plot_ly(mtcars, y = mtcars$wt, type = "histogram")
O eixo Z pode ser usado para gráficos 3d ou heatmaps
plot_ly(z = ~volcano, type = "heatmap")
plot_ly(z = ~volcano, type = "surface")
Este pacote suporta encadeamento de funções com pipe:
plot_ly(economics, x = ~date, color = I("black")) %>%
add_lines(y = ~uempmed) %>%
add_lines(y = ~psavert, color = I("red"))
LS0tCnRpdGxlOiAiUiA8LSIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQo8c3R5bGU+Cmgzewpib3JkZXItYm90dG9tOmRhc2hlZCAxcHggIzk5OTk5OTsKcGFkZGluZy1ib3R0b206MTBweDsKfQpoNHsKY29sb3I6IzQ0NDQ0NDsKfQo8L3N0eWxlPgoKPGJyIC8+Cgo8aHIgLz4KCiMjIyPDjW5kaWNlCjx1bD4KICA8bGk+W1VzbyBiw6FzaWNvIGRhIGxpbmd1YWdlbV0oI2Jhc2ljbyk8L2xpPgogIDx1bD4KICA8bGk+W1ZhcmnDoXZlaXNdKCN2YXJpYXZlaXMpPC9saT4KICA8bGk+W1ZldG9yZXNdKCN2ZXRvcmVzKTwvbGk+CiAgPGxpPltPcGVyYcOn4bq9b3MgY29tIHZldG9yZXNdKCN2ZWNfb3BzKTwvbGk+CiAgPGxpPltNYXRyaXplc10oI21hdHJpemVzKTwvbGk+CiAgPGxpPltPcGVyYcOnw7VlcyBjb20gbWF0cml6ZXNdKCNtYXRyaXhfb3BzKTwvbGk+CiAgPC91bD4KICAKICA8bGk+W0Z1bsOnw7VlcyBpbnRlcm5hc10oI2ludF9mdW5jKTwvbGk+CiAgPHVsPgogIDxsaT5bRnVuw6fDtWVzIGludGVybmFzIHBhcmEgYXJpdG3DqXRpY2EgZW0gZ2VyYWxdKCNpbnRfZnVuY19nZXJhbCk8L2xpPgogIDwvdWw+CiAgCiAgPGxpPltBcGxpY2HDp8OjbyBlbSBlc3RhdMOtc3RpY2FdKCNhcGxpY19lc3RhdCk8L2xpPgogIDx1bD4KICA8bGk+W0Rlc3ZpbyBQYWRyw6NvXSgjZGVzdmlvX3BhZHJhbyk8L2xpPgogIDxsaT5bUmVncmVzc8OjbyBMaW5lYXJdKCNyZWdyZXNzYW9fbGluZWFyKTwvbGk+CiAgPC91bD4KICAKICA8bGk+W0dyYWZpY29zXSgjZ3JhZmljb3MpPC9saT4KICA8dWw+CiAgPGxpPltQbG90XSgjcGxvdCk8L2xpPgogIDxsaT5bQm94cGxvdF0oI2JveCk8L2xpPgogIDxsaT5bSGlzdG9ncmFtYV0oI2hpc3QpPC9saT4KICA8L3VsPgogIAogIDxsaT5bUGFjb3RlcyBlc3NlbmNpYWlzXSgjcGFja2FnZXMpPC9saT4KICA8dWw+CiAgPGxpPltEcGx5cl0oI2RwbHlyKTwvbGk+CiAgPHVsPgogIDxsaT5bU2VsZWN0XSgjc2VsZWN0KTwvbGk+CiAgPGxpPltGaWx0ZXJdKCNmaWx0ZXIpPC9saT4KICA8bGk+W0FycmFuZ2VdKCNhcnJhbmdlKTwvbGk+CiAgPGxpPltNdXRhdGVdKCNtdXRhdGUpPC9saT4KICA8bGk+W1BpcGVzXSgjcGlwZSk8L2xpPgogIDwvdWw+CiAgPC91bD4KICAKICA8bGk+W1BhY290ZXMgcGFyYSBncsOhZmljb3NdKCNwYWNvdGVzX2dyYWZpY29zKTwvbGk+CiAgPHVsPgogIDxsaT5bR2dwbG90Ml0oI2dncGxvdDIpPC9saT4KICA8bGk+W1Bsb3RseV0oI3Bsb3RseSk8L2xpPgogIDwvdWw+CiAgCjwvdWw+Cgo8aHIgLz4KCiMjIyA8YSBuYW1lPSJiYXNpY28iPjwvYT5Vc28gYsOhc2ljbyBkYSBsaW5ndWFnZW0KIyMjIyA8YSBuYW1lPSJ2YXJpYXZlaXMiPjwvYT5BdHJ1YnVpw6fDo28gZGUgdmFyacOhdmVpcwoKYGBge3J9Cm4gPC0gKCg1ICsgNSkgKiA0KSAvIDIKbgpzcXJ0KG4gKyA1KSAtPiBzcQpzcQpzcSBeIDMKYGBgCjxiciAvPgoKIyMjPGEgbmFtZT0idmV0b3JlcyI+PC9hPiBWZXRvcmVzCmBgYHtyfQp2IDwtIGMoMSwyLDMsNCw1KQp2CnYgPC0gMTo1CnYKc2VxKDUpIC0+IHYKdgp2IDwtIHNlcS5pbnQoZnJvbSA9IDEsIHRvID0gNSwgYnkgPSAxKQp2CmBgYAo8YnIgLz4KVmV0b3JlcyBwb2RlbSB0ZXIgc2V1cyDDrW5kaWNlcyBub21lYWRvczoKYGBge3J9CnZfbmFtZXMgPC0gYygidW0iLCAiZG9pcyIsICJ0csOqcyIsICJxdWF0cm8iLCAiY2luY28iKQpuYW1lcyh2KSA8LSB2X25hbWVzCnYKYGBgCgoKIyMjIzxhIG5hbWU9InZlY19vcHMiPjwvYT4gT3BlcmHDp8O1ZXMgY29tIHZldG9yZXMKRW0gdW1hIG9wZXJhw6fDo28gZW50cmUgdW0gdmV0b3IgZSB1bSBlc2NhbGFyIHRvZG9zIG9zIMOtbmRpY2VzIHNvZnJlbSBhIG9wZXJhw6fDo286CmBgYHtyfQp2ICogbgoKdiAqKiAyCmBgYArDiSBwb3Nzw612ZWwgb3BlcmFyIMOtbmRpY2VzIGVzcGVjw61maWNvczoKYGBge3J9CnZpcyA8LSB2WzFdICsgdlszXQp2aXMKYGBgClF1bmFkbyBhIG9wZXJhw6fDo28gw6kgZmVpdGEgZW50cmUgZG9pcyB2ZXRvcmVzIGRvIG1lc21vIHRhbWFuaG8gdG9kb3Mgb3MgaW5kaWNlcyBzw6NvIG9wZXJhZG9zIHBlbG9zIGluZGljZXMgZG8gb3V0cm8gdmV0b3I6CmBgYHtyfQp2MiA8LSBjKDIsMiwyLDIsMikKdiArdjIKYGBgClNlIG9zIHRhbWFuaG9zIGZvcmVtIGRpZmVyZW50ZXMgYSBvcGVyYcOnw6NvIMOpIHJlYWxpemFkYSBjb20gdW0gYXZpc28uIE9zIHZhbG9yZXMgZG8gdmV0b3IgbWVub3Igc8OjbyByZXBldGlkb3MgbmEgb3BlcmHDp8OjbzoKYGBge3J9CnYyIDwtIGMoMywzLDMpCnYgKiB2MgpgYGAKCiMjI0ZpbHRyYWdlbQpWZXRvcmVzIHBvZGVtIHNlciBmaWx0cmFkb3MgcG9yIHJhbmdlCmBgYHtyfQp2WzE6M10KYGBgClRhbWLDqW0gcG9kZW0gc2VyIGZpbHRyYWRvcyBhdHJhdsOpcyBkZSBjb25kaWNpb25haXMuIE8gY2FzbyBhYmFpeG8gcmV0b3JuYSB1bSB2ZXRvciBkZSBib2xlYW5vcyBxdWUgc2F0aXNmYcOnYSBhIGNvbmRpw6fDo286CmBgYHtyfQp2ID4gMwpgYGAKUGFyYSByZXRvcm5hciBvcyB2YWxvcmVzIGVzdGUgdmV0b3IgZGUgYm9sZWFub3MgZGV2ZSBpciBkZW50cm8gZGEgaW5kZXhhw6fDo286CmBgYHtyfQp2W3Y+M10KYGBgCjxiciAvPgoKIyMjPGEgbmFtZT0ibWF0cml6ZXMiPjwvYT4gTWF0cml6ZXMKTWF0cml6ZXMgc8OzIHBvZGVtIHRlciB1bSB0aXBvIGRlIHZhbG9yLiBJbmljaWFsaXphw6fDo286CmBgYHtyfQptMSA8LSBtYXRyaXgoMToyMCwgbnJvdyA9IDQsIG5jb2wgPSA1KQptMQpgYGAKIyMjIzxhIG5hbWU9Im1hdHJpeF9vcHMiPjwvYT4gT3BlcmHDp8O1ZXMgY29tIG1hdHJpemVzCkEgbMOzZ2ljYSBwYXJhIG9wZXJhw6fDtWVzIGNvbSBlc2NhbGFyZXMgw6kgYSBtZXNtYSBwYXJhIHZldG9yZXM6CmBgYHtyfQptMSAqIDUKYGBgCkVtIG9wZXJhw6fDtWVzIGNvbSB2ZXRvcmVzIGUgbWF0cml6ZXMgY2FkYSBjb2x1bmEgZGEgbWF0cml6IMOpIHBlcmNvcnJpZGEgcGVsbyB2ZXRvciBlbSBvcmRlbSBlIGRlcG9pcyBzZSByZXBldGU6CmBgYHtyfQptMSAqIHYKYGBgCgpPcyB2YWxvcmVzIGRlIGR1YXMgbWF0cml6ZSBwb2RlbSBzZXIgb3BlcmFkb3Mgc2UgZWxhcyBwb3NzdWlyZW0gYSBtZXNtYSBxdWFudGlkYWRlIGRlIGxpbmhhcyBlIGNvbHVuYXM6CgpgYGB7cn0KbTIgPC0gbWF0cml4KDIwOjM5LCBucm93ID0gNCwgbmNvbCA9IDUpCm0xICogbTIKbTEgKyBtMgpgYGAKClBhcmEgZGUgZmF0byBtdWx0aXBsY2FyIGR1YXMgbWF0cml6ZXMgYSByZWdyYSBtYXRlbcOhdGljYSBwcmVjaXNhIHNlIHJlc3BlaXRhZGEgKGwxID0gYzIpLiBPIG9wZXJhZG9yIGNvcnJldG8gw6kgJSolCgpgYGB7cn0KbTMgPC0gbWF0cml4KDE6MjAsIG5yb3cgPSA1LCBuY29sID0gNCkKbTEgJSolIG0zCmBgYAoKCjxiciAvPgoKIyMjPGEgbmFtZT0iaW50X2Z1bmMiPjwvYT4gRnVuw6fDtWVzIEludGVybmFzCiMjIyM8YSBuYW1lPSJpbnRfZnVuY19nZXJhbCI+PC9hPiBGdW7Dp8O1ZXMgcGFyYSBhcml0aW3DqXRpY2EgZW0gZ2VyYWwKCjxiciAvPgoKIyMjI1NvbWEgKHN1bSkuIApTb21hIHRvZG9zIG9zIHZhbG9yZXMgZGUgdW0gdmV0b3IKYGBge3J9CnJhbmRvbV92ZWMgPC0gc2FtcGxlKDMwKQpyYW5kb21fdmVjCnN1bShyYW5kb21fdmVjKQpgYGAKPGJyIC8+CgpUYW1iw6ltIHBvZGUgc2VyIHV0aWxpemFkbyBqdW50byBjb20gZmlsdHJhZ2VtLCBwYXJhIGNvbnRhciBhIHF1YW50aWRhZGUgZGUgb2NvcnJlbmNpYXMgZGFkYSB1bWEgZGV0ZXJtaW5hZGEgY29uZGnDp8OjbzoKYGBge3J9CnN1bShtdGNhcnMkZ2VhciA9PSA0KQpgYGAKTmVzdGUgY2FzbyBvIHJlc3VsdGFkbyBpbmRpY2FkIHF1ZSBhIHRhYmVsYSAibXRjYXJzIiBwb3NzdWkgMTIgb2NvcnJlbmNpYXMgY3VqYSBjb2x1bmEgZ2VhciDDqSBpZ2F1YWwgYSA0LCBvdSBzZWphLCAxMiBjYXJyb3MgZGUgNCBtYXJjaGFzCgo8YnIgLz4KCiMjIyNNw6lkaWEgQXJpdGltw6l0aWNhIHPDrW1wbGVzCiMjJFxiYXJ7eH0gPSBcZnJhY3tcc3VtX3tpPTF9Xm4geF97aX19e259JAoKYGBge3J9CnZlY19tIDwtIGMoMSwyLDMsNCw1LDYsNyw4LDksMTAsMzApCm1lYW4odmVjX20pCgpgYGAKIyMjI01lZGlhbmEKCmBgYHtyfQptZWRpYW4odmVjX20pCmBgYAoKCgojIyMgPGEgbmFtZT0iYXBsaWNfZXN0YXQiPjwvYT4gQXBsaWNhw6fDo28gZW0gZXN0YXTDrXN0aWNhCgo8YnIgLz4KCiMjIyM8YSBuYW1lPSJkZXN2aW9fcGFkcmFvIj48L2E+RGVzaXZvIHBhZHLDo28KIyMkXHNpZ21hID0gXHNxcnR7XGZyYWN7XHN1bV97aT0xKHhpX3tpfSAtIFxiYXJ7eH0pXjJ9XntufX17bn19JAoKPGJyIC8+CgpgYGB7cn0KdmVjX3ZhciA8LSBzYW1wbGUoMjApCnZlY192YXIKc2QodmVjX3ZhcikKCmBgYAoKCjxiciAvPgoKIyMjIDxhIG5hbWU9InJlZ3Jlc3Nhb19saW5lYXIiPjwvYT4gUmVncmVzc8OjbyBMaWFuZWFyCgojIyRZX3tpfSA9IFxiZXRhX3swfStcYmV0YV97MX1YX3tpfStceGkkCgpFeGVtcGxvOiBSZWxhw6fDo28gZW50cmUgcGVzbyBlIGFsdHVyYSBlbSBtdWxoZXJlczoKYGBge3J9CndvbWVuCnJlZ1dvbWVuIDwtIGxtKHdvbWVuJGhlaWdodCB+IHdvbWVuJHdlaWdodCkKc3VtbWFyeShyZWdXb21lbikKYGBgClBPTlRPUyBJTVBPUlRBTlRFUzo8YnIgLz4KbyBwLXZhbHVlIG8gbsOtdmVsIGRlIGNvb3JyZWxhw6fDo28gZW50cmUgYXMgdmFyacOhdmVpcy4gQWJhaXhvIGRlIDAuMDUgZXN0w6EgZGVudHJvIGRvIGludGVydmFsbyBkZSBjb25maWFuw6dhIGRlIDk1JTxiciAvPgpPIFIgYWp1c3RhZG8gaW5kaWNhIGEgY2FwYWNpZGFkZSBkZSBleHBsaWNhw6fDo28gZGFzIHZhcmnDoXZlaXMgbm8gbW9kZWxvLjxiciAvPgpPIHJlc3VsdGFkbyBwb3NzdWkgdW0gcC12YWx1ZSBleHRyZW1hbWVudGUgYmFpeG86ICQxLjkxXnstMTR9JCwgb3Ugc2VqYSwgYWx0YSBjb29ycmVsYcOnw6NvIGVudHJlIGFzIHZhcmnDoXZlaXMuPGJyIC8+Ck8gUiBhanVzdGFkbyBkZSAwLjk5MDMgaW5kaWNhIHF1ZSBlc3RlIG1vZGVsbyB0ZW0gY2FwYWNpZGEgZGUgZXhwbGljYcOnw6NvIGVtIDk5LjAzJS4KCgojIyA8YSBuYW1lPSJncmFmaWNvcyI+PC9hPkdyw6FmaWNvcwoKPGJyIC8+CgojIyMgPGEgbmFtZT0icGxvdCI+PC9hPiBQbG90ClBsb3RhIGRlIGFjb3JkbyBjb20gYSBzZXJpZSBkZSBkYWRvcy4gTm8gZXhlbXBsbyBhYmFpeG8gY2FkYSB2YWxvciDDqSByZXByZXNlbnRhZG8gcG9yIHVtIHBvbnRvIG5vIGVpeG8gY2FydGVzaWFubzoKYGBge3J9CnBsb3QoeCA9IGNhcnMkc3BlZWQsIHkgPSBjYXJzJGRpc3QsIG1haW4gPSAiRGlzdMOibmNpYXMgZGUgcGFyYWRhIiwgeGxhYiA9ICJWZWxvY2lkYWRlIiwgeWxhYiA9ICJEaXN0w6JuY2lhIikKI1RhbWLDqW0gw6kgcG9zc8OtdmVsIGludGVyZmVyaXIgbm8gZ3LDoWZpY28gcXVlIGZvaSBwbG90YWRvLiBPcyBkb2lzIGNvbWFuZG9zIGRldmVtIHNlciBleGVjdXRhZG9zIGp1bnRvcy4KbGluZXMgKGMoNSwyNSksYyg1LDgwKSwgY29sPSdyZWQnKQpgYGAKCk91dHJvcyB0aXBvcyBkZSBzw6lyaWVzIGV4aWJpcsOjbyBvdXRyb3MgdmlzdWFpczoKYGBge3J9CnBsb3QoVUtEcml2ZXJEZWF0aHMpCmBgYAoKQW8gcGxvdGFyIG8gcmVzdWx0YWRvIGRlIHVtYSByZWdyZXNzw6NvIGxpbmVhciB2w6FyaW9zIHRpcG9zIGRlIGdyw6FmaWNvcyBzZXLDo28gZXhpYmlkb3M6CmBgYHtyfQpwbG90KHJlZ1dvbWVuKQpgYGAKCgojIyMgPGEgbmFtZT0iYm94Ij48L2E+IEJveHBsb3QKUmVwcmVzZW50YSBncmFmaWNhbWVudGUgb3MgdmFsb3JlcyBkbyBtw61uaW1vLCAxLDIgZSAzIHF1YXJ0aWwsIG1lZGlhbmEgZSBtw6F4aW1vLgpgYGB7cn0KYm94cGxvdChhaXJxdWFsaXR5KQoKYGBgCgojIyMgPGEgbmFtZT0iaGlzdCI+PC9hPiBIaXN0b2dyYW1hCkhpc3RvZ3JhbWEgZGFzIGZyZXF1ZW5jaWFzIGRlIHVtIGRhdGFzZXQKYGBge3J9Cmhpc3QobXRjYXJzJG1wZykKYGBgCgojIyMgPGEgbmFtZT0iZHBseXIiPjwvYT4gRHBseXIKIyMjIyA8YSBuYW1lPSJzZWxlY3QiPjwvYT4gU2VsZWN0ClJldG9ybmEgdW0gc3Vic2V0IGNvbSBhIHNsZcOnw6NvIGRlIGNvbHVuYXMgZmlsdHJhZGFzCmBgYHtyfQpzZWxlY3QobXRjYXJzLCBtcGcsaHAscXNlYyxnZWFyKQpgYGAKVGFtYsOpbSBwb2RlIHNlciB1c2FkbyBjb20gcmFuZ2VzOgpgYGB7cn0Kc2VsZWN0KG10Y2FycywgaHA6Z2VhcikKYGBgCjxiciAvPgoKIyMjIyA8YSBuYW1lPSJmaWx0ZXIiPjwvYT4gRmlsdGVyCkZpbHRyYSBsaW5oYXMgZGUgYWNvcmRvIGNvbSBjb25kacOnw7Vlcy4gT3BlcmFkb3JlcyBiaW7DoXJpb3MgcG9kZW0gc2VyIHV0aWxpemFkb3MKYGBge3J9CmZpbHRlcihtdGNhcnMsIGhwID4gMTAwLCB3dCA8IDMuMDAwIHwgcXNlYyA+IDIwLjEpCmBgYAo8YnIgLz4KCiMjIyMgPGEgbmFtZT0iYXJyYW5nZSI+PC9hPiBBcnJhbmdlCk9yZGVuYSBhIHRhYmVsYSBkZSBhY29yZG8gY29tIGFzIHZhcmnDoXZlaXMgZm9ybmVjaWRhcy4gTm8gY2FzbyBhYmFpeG8gbyBwcmltZWlybyBjcml0w6lyaW8gZGUgb3JkZW5hw6fDo28gw6kgYSBxdWFudGlkYWRlIGRlIGNpbGluZHJvcyBjcmVzY2VudGUgZSBvIHNlZ3VuZG8gw6kgYSBxdWFudGlkYWRlIGRlIG1hcmNoYXMgZGVjcmVzY2VudGUuCmBgYHtyfQphcnJhbmdlKG10Y2FycywgY3lsLCBkZXNjKGdlYXIpKQpgYGAKPGJyIC8+CgojIyMjIDxhIG5hbWU9ImFycmFuZ2UiPjwvYT4gTXV0YXRlCkluc2VyZSBub3ZhcyB2YXJpw6F2ZWlzIG5hIHRhYmVsYS4gw4kgcG9zc8OtdmVsIHV0aWxpemFyIG91dHJhcyB2YXJpw6F2ZWlzIGNvbW8gYmFzZSBwYXJhIG9zIHZhbG9yZXMKCmBgYHtyfQptdXRhdGUoVVNBcnJlc3RzLCBtdXJkZXJfcHJvcCA9IE11cmRlciAvIChBc3NhdWx0ICsgUmFwZSkpCmBgYAo8YnIgLz4KCiMjIyMgPGEgbmFtZT0icGlwZSI+PC9hPiBQaXBlcwrDiSBwb3Nzw612ZWwgZW5jYWRlYXIgdG9kYXMgZXN0YXMgZnVuw6fDtWVzIGNvbSB1bSBwaXBlICggJT4lICk6CmBgYHtyfQphaXJxdWFsaXR5ICU+JSBmaWx0ZXIoTW9udGggPT0gOCkgJT4lIHNlbGVjdChPem9uZSxUZW1wLFdpbmQpICU+JSBtdXRhdGUodmVudG9fYW9fcXVhZHJhZG8gPSBXaW5kICoqIDIpCmBgYAoKPGJyIC8+CiMjIyA8YSBuYW1lPSJwYWNvdGVzX2dyYWZpY29zIj48L2E+IFBhY290ZXMgcGFyYSBncsOhZmljb3MKIyMjIyA8YSBuYW1lPSJnZ3Bsb3QyIj48L2E+IEdncGxvdDIKQ3JpYSBncsOhZmljb3MgdmlzdWFsbWVudGUgYWdyYWTDoXZlaXMgY29tIGJhc3RhbnRlIGNvbnRyb2xlLiBmdW5jaW9uYSBjb20gYSBzZWd1aW50ZSBzaW50YXhlOjxiciAvPgpnZ3Bsb3QyKGRhdGFzZXQsIGFlcyh2YVgsdmFyWSwuLi4pKSArIGZ1bsOnw6NvX2RlX3Bsb3RhZ2VtKCkgKyBmdW7Dp8Ojb19kZV9wbG90YWdlbSgpICsgLi4uPGJyIC8+CnByaW1laXJvIMOpIGNyaWFkYSBhIGFyZWEgZGUgcGxvdGFnZW0gY29tIG9zIHBhcsOibWV0cm9zIGLDoXNpY29zLiBFbSBzZWd1aWRhIGNhZGEgZnVuw6fDo28gc29tYWRhIMOpIGFkY2lvbmFkYSBhbyBwbG90LgoKYGBge3J9CmdncGxvdCh3b21lbiwgYWVzKHdvbWVuJGhlaWdodCx3b21lbiR3ZWlnaHQpKSArIGdlb21fcG9pbnQoY29sPSdyZWQnKSArIGdlb21fcGF0aChjb2w9JyMzMzMzMzMnKQpnZ3Bsb3QoY2FycywgYWVzKGNhcnMkc3BlZWQsY2FycyRkaXN0KSkgKyBnZW9tX2NvdW50KCkKYGBgCgoKCjxiciAvPgoKIyMjIyA8YSBuYW1lPSJwbG90bHkiPjwvYT4gUGxvdGx5CkNyaWEgZ3LDoWZpY29zIGludGVyYXRpdm9zIGNvbSBleGNlbGVudGVzIHJlY3Vyc29zLCBtYXMgZnVuY2lvbmEgY29tIHNpc3RlbWEgZGUgdmlzdWFsaXphZG9yLiBTZSBvIHRpcG8gZGUgZ3LDoWZpY28gbsOjbyBmb3IgZm9ybmVjaWRvIGVsZSB0ZW50YXLDoSBkZWR1emlyPGJyIC8+Cm9iczogbmVzdGUgcGFjb3RlIGNhcmFjdGVyZSAnficgbsOjbyBzaWduaWZpY2EgZW0gZnVuw6fDo28gZGUuCmBgYHtyfQpwbG90X2x5KGVjb25vbWljcywgeCA9IH5kYXRlLCB5ID0gfnBvcCkKcGxvdF9seShtdGNhcnMsIHkgPSBtdGNhcnMkd3QsIHR5cGUgPSAiaGlzdG9ncmFtIikKYGBgCk8gZWl4byBaIHBvZGUgc2VyIHVzYWRvIHBhcmEgZ3LDoWZpY29zIDNkIG91IGhlYXRtYXBzCmBgYHtyfQpwbG90X2x5KHogPSB+dm9sY2FubywgdHlwZSA9ICJoZWF0bWFwIikKcGxvdF9seSh6ID0gfnZvbGNhbm8sIHR5cGUgPSAic3VyZmFjZSIpCmBgYAoKRXN0ZSBwYWNvdGUgc3Vwb3J0YSBlbmNhZGVhbWVudG8gZGUgZnVuw6fDtWVzIGNvbSBwaXBlOgpgYGB7cn0KcGxvdF9seShlY29ub21pY3MsIHggPSB+ZGF0ZSwgY29sb3IgPSBJKCJibGFjayIpKSAlPiUKIGFkZF9saW5lcyh5ID0gfnVlbXBtZWQpICU+JQogYWRkX2xpbmVzKHkgPSB+cHNhdmVydCwgY29sb3IgPSBJKCJyZWQiKSkKYGBgCgo=